package com.offcn.user.controller;

import com.alibaba.fastjson.JSON;
import com.offcn.entity.PageResult;
import com.offcn.entity.Result;
import com.offcn.entity.StatusCode;
import com.offcn.user.pojo.User;
import com.offcn.user.service.UserService;
import com.offcn.utils.JwtUtil;
import com.offcn.utils.PhoneFormatCheckUtils;
import io.swagger.annotations.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.crypto.bcrypt.BCrypt;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

/****
 * @Author:ujiuye
 * @Description:
 * @Date 2021/2/1 14:19
 *****/
@Api(tags = "UserController")
@RestController
@RequestMapping("/user")
@CrossOrigin
public class UserController {

    @Autowired
    private UserService userService;

    // 通过用户名来获取用户
    @GetMapping({"/{username}","/load/{username}"})
    public Result<User> findByUsername(@PathVariable String username){
        User user = userService.findByUsername(username);
        return new Result<>(true,StatusCode.OK,"查询成功",user);
    }
    /**
     * @param: 用户通过页面表单中填写的用户名和密码在后台使用username和password来接收
     * @description: 用户登录验证
     * @analyze:
     * 1.获取用户名和密码
     * 2. 判断用户名和密码在数据库中是否存在
     *    存在：登录成功
     *    存储登录成功用户数据  将用户信息封装到jwt，作为token使用，redis中存储对应的数据
     *    不存在：登录失败
     */
    @RequestMapping("/login")
    public Result login(String username, String password, HttpServletResponse response){
        User user = userService.findByUsername(username);
        if (user == null) {
            return new Result(false,StatusCode.LOGINERROR,"用户名和密码错误");
        }
        if (BCrypt.checkpw(password,user.getPassword())) {
            // 存储登录成功用户数据  将用户信息封装到jwt，作为token使用
            /**
             * @param: (随机数id,封装用户的信息,jwt的到期时间)
             * @return: string类型的jwt——也可以理解为token
             * @description: 行加密：createJwt(String id,String userInfo,Long exp)
             * @analyze: 封装用户的信息(用户的角色,哪个用户(用户名可以获取密码),显式状态)
             */
            Map<String, String> userInfo = new HashMap<>();
            userInfo.put("role","user");
            userInfo.put("username",username);
            userInfo.put("status","LOGIN_SUCCESS");
            // 将map对象转为json
            String info = JSON.toJSONString(userInfo);
            String jwt = JwtUtil.createJwt(UUID.randomUUID().toString(), info, null);

            //将jwt添加到cookies中
            Cookie cookie = new Cookie("Authorization", jwt);
            cookie.setPath("/");   // 这一步的目的是在网关中登录和注册验证路径
            response.addCookie(cookie);

            return new Result(true,StatusCode.OK,"登录成功",jwt);
        }
        return new Result(false,StatusCode.LOGINERROR,"用户名和密码错误");
    }

    @GetMapping("/createSmsCode")
    public Result createSmsCode(String mobile){
        // 验证手机号是否合法
        if(!PhoneFormatCheckUtils.isChinaPhoneLegal(mobile)){
            return new Result(false,StatusCode.ERROR,"手机号格式错误");
        }
        // 手机格式正确
        userService.createSmsCode(mobile);
        return new Result(true,StatusCode.OK,"验证码发送成功");
    }

    /***
     * User分页条件搜索实现
     * @param user
     * @param page
     * @param size
     * @return
     */
    @ApiOperation(value = "User条件分页查询",notes = "分页条件查询User方法详情",tags = {"UserController"})
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "path", name = "page", value = "当前页", required = true),
            @ApiImplicitParam(paramType = "path", name = "size", value = "每页显示条数", required = true)
    })
    @PostMapping(value = "/search/{page}/{size}" )
    public Result<PageResult<User>> findPage(@RequestBody(required = false) @ApiParam(name = "User对象",value = "传入JSON数据",required = false) User user, @PathVariable  int page, @PathVariable  int size){
        //调用UserService实现分页条件查询User
        PageResult<User> pageResult = userService.findPage(user, page, size);
        return new Result(true,StatusCode.OK,"查询成功",pageResult);
    }

    /***
     * User分页搜索实现
     * @param page:当前页
     * @param size:每页显示多少条
     * @return
     */
    @ApiOperation(value = "User分页查询",notes = "分页查询User方法详情",tags = {"UserController"})
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "path", name = "page", value = "当前页", required = true),
            @ApiImplicitParam(paramType = "path", name = "size", value = "每页显示条数", required = true)
    })
    @GetMapping(value = "/search/{page}/{size}" )
    public Result<PageResult<User>> findPage(@PathVariable  int page, @PathVariable  int size){
        //调用UserService实现分页查询User
        PageResult<User> pageResult = userService.findPage(page, size);
        return new Result<PageResult<User>>(true,StatusCode.OK,"查询成功",pageResult);
    }

    /***
     * 多条件搜索品牌数据
     * @param user
     * @return
     */
    @ApiOperation(value = "User条件查询",notes = "条件查询User方法详情",tags = {"UserController"})
    @PostMapping(value = "/search" )
    public Result<List<User>> findList(@RequestBody(required = false) @ApiParam(name = "User对象",value = "传入JSON数据",required = false) User user){
        //调用UserService实现条件查询User
        List<User> list = userService.findList(user);
        return new Result<List<User>>(true,StatusCode.OK,"查询成功",list);
    }

    /***
     * 根据ID删除品牌数据
     * @param id
     * @return
     */
    @ApiOperation(value = "User根据ID删除",notes = "根据ID删除User方法详情",tags = {"UserController"})
    @ApiImplicitParam(paramType = "path", name = "id", value = "主键ID", required = true, dataType = "Long")
    @DeleteMapping(value = "/{id}" )
    public Result delete(@PathVariable Long id){
        //调用UserService实现根据主键删除
        userService.delete(id);
        return new Result(true,StatusCode.OK,"删除成功");
    }

    /***
     * 修改User数据
     * @param user
     * @param id
     * @return
     */
    @ApiOperation(value = "User根据ID修改",notes = "根据ID修改User方法详情",tags = {"UserController"})
    @ApiImplicitParam(paramType = "path", name = "id", value = "主键ID", required = true, dataType = "Long")
    @PutMapping(value="/{id}")
    public Result update(@RequestBody @ApiParam(name = "User对象",value = "传入JSON数据",required = false) User user,@PathVariable Long id){
        //设置主键值
        user.setId(id);
        //调用UserService实现修改User
        userService.update(user);
        return new Result(true,StatusCode.OK,"修改成功");
    }

    /***
     * 新增User数据
     * @param user
     * @return
     */
    @ApiOperation(value = "User添加",notes = "添加User方法详情",tags = {"UserController"})
    @PostMapping("/regist")
    public Result add(@RequestBody  @ApiParam(name = "User对象",value = "传入JSON数据",required = true) User user){

        boolean flag = userService.checkSmsCode(user.getPhone(), user.getCode());

        if (!flag){
            return new Result(false,StatusCode.ERROR,"验证码错误，请重试");
        }

        //调用UserService实现添加User
        userService.add(user);
        return new Result(true,StatusCode.OK,"注册成功");
    }

    /***
     * 根据ID查询User数据
     * @param id
     * @return
     */
    @ApiOperation(value = "User根据ID查询",notes = "根据ID查询User方法详情",tags = {"UserController"})
    @ApiImplicitParam(paramType = "path", name = "id", value = "主键ID", required = true, dataType = "Long")
    @GetMapping("/{id}")
    public Result<User> findById(@PathVariable Long id){
        //调用UserService实现根据主键查询User
        User user = userService.findById(id);
        return new Result<User>(true,StatusCode.OK,"查询成功",user);
    }

    /***
     * 查询User全部数据
     * @return
     */
    @PreAuthorize("hasAnyAuthority('admin')")  // 有admin身份才可以访问该方法
    @ApiOperation(value = "查询所有User",notes = "查询所User有方法详情",tags = {"UserController"})
    @PostMapping("/findAll")
    public Result<List<User>> findAll(){
        //调用UserService实现查询所有User
        List<User> list = userService.findAll();
        return new Result<List<User>>(true, StatusCode.OK,"查询成功",list) ;
    }
}
